//@author A0099223B

import java.util.ArrayList;
import java.util.Date;

public class EditParser extends Parser {
	private static final ArrayList<String> UNUSABLE_TAGS = new ArrayList<String>() {
		{
			add(TAG_KEYWORD);
			add(TAG_DONE);
			add(TAG_NOTDONE);
		}
	};

	protected static Command parse(String userInput)
			throws InvalidInputException {
		assert (userInput.toLowerCase().startsWith(COMMAND_EDIT));

		ArrayList<String> unparsedWords = getWordsInCommandDetails(userInput);
		checkForMissingDetails(unparsedWords);

		String title = attemptToObtainTitle(unparsedWords);
		EditCommand editCommand = new EditCommand();
		if (isEmptyString(title)) {
			setAsIdBasedCommand(unparsedWords, editCommand);
		} else {
			setAsTitleBasedCommand(title, unparsedWords, editCommand);

		}
		return editCommand;
	}

	private static String attemptToObtainTitle(ArrayList<String> unparsedWords) {
		return extractWordsBeforeNextTag(unparsedWords);
	}

	private static void setAsIdBasedCommand(ArrayList<String> unparsedWords,
			EditCommand editCommand) throws InvalidInputException {

		checkTags(unparsedWords);
		editCommand.taskId = obtainTaskId(unparsedWords);

		if (unparsedWords.isEmpty()) {
			setAsPopupOpenCommand(editCommand);
		} else {
			fillNewTaskDetails(editCommand, unparsedWords);
		}
	}

	private static int obtainTaskId(ArrayList<String> unparsedWords)
			throws InvalidInputException {
		String id = extractTaggedClause(TAG_ID, unparsedWords);
		ifNullNoTaskReferenced(id); 
		return parseId(id);

	}

	private static void setAsTitleBasedCommand(String title,
			ArrayList<String> unparsedWords, EditCommand editCommand)
			throws InvalidInputException {

		ensureNoIdReference(unparsedWords);
		editCommand.taskTitle = title;
		if (unparsedWords.isEmpty()) {
			setAsPopupOpenCommand(editCommand);
		} else {
			checkTags(unparsedWords);
			fillNewTaskDetails(editCommand, unparsedWords);
		}

	}

	private static void setAsPopupOpenCommand(EditCommand editCommand) {
		editCommand.isGuiOpenCommand = true;
	}

	private static void checkTags(ArrayList<String> unparsedWords)
			throws InvalidInputException {

		checkForUnusableStringTags(UNUSABLE_TAGS, unparsedWords, COMMAND_EDIT);
		checkForRepeatingTags(unparsedWords);
	}

	private static void fillNewTaskDetails(EditCommand editCommand,
			ArrayList<String> unparsedWords) throws InvalidInputException {

		editCommand.newTaskDetails = new Task();

		while (!unparsedWords.isEmpty()) {
			String tag = removeFirstWordFromArray(unparsedWords);

			if (isTaggedAsProject(tag)) {
				setProjectVariables(editCommand, tag);
			} else {
				switchToCorrectAttribute(editCommand, unparsedWords, tag);
			}

		}

		checkForReversedDates(editCommand.newTaskDetails.startTime,
				editCommand.newTaskDetails.endTime);
	}

	private static void setProjectVariables(EditCommand editCommand, String tag) {
		editCommand.isEditingProject = true;
		editCommand.newTaskDetails.project = getNewProject(tag);
	}

	private static String getNewProject(String marker) {
		String project = Task.EMPTY_STRING;
		try {
			project = getProjectName(marker);
		} catch (InvalidInputException e) {
			// Do Nothing
		}

		return project;
	}

	private static void switchToCorrectAttribute(EditCommand editCommand,
			ArrayList<String> unparsedWords, String tag)
			throws InvalidInputException {
		checkIfTag(tag);

		String value = extractWordsBeforeNextTag(unparsedWords);
		value = setEmptyStringToEmptyValue(value);
		switch (tag.toLowerCase()) {
		case TAG_START_TIME:
			setStartTimeVariables(editCommand, tag, value);
			break;
		case TAG_END_TIME:
			setEndTimeVariables(editCommand, tag, value);
			break;
		case TAG_PLACE:
			setPlaceVariables(editCommand, value);
			break;
		case TAG_DESCRIPTION:
			setDescriptionVariables(editCommand, value);
			break;
		case TAG_TITLE:
			setTitleVariables(editCommand, tag, value);
			break;
		}

	}

	private static String setEmptyStringToEmptyValue(String value) {
		if (isEmptyString(value)) {
			return Task.EMPTY_STRING;
		}

		return value;
	}

	private static void setStartTimeVariables(EditCommand editCommand,
			String tag, String value) throws InvalidInputException {
		editCommand.isEditingStartTime = true;
		editCommand.newTaskDetails.startTime = getNewTime(value, tag);
	}

	private static void setEndTimeVariables(EditCommand editCommand,
			String tag, String value) throws InvalidInputException {
		editCommand.isEditingEndTime = true;
		editCommand.newTaskDetails.endTime = getNewTime(value, tag);
	}

	private static Date getNewTime(String value, String marker)
			throws InvalidInputException {
		if (value == Task.EMPTY_STRING || isEmptyString(value)) {
			return Task.EMPTY_TIME;
		}

		return parseTime(value, marker);
	}

	private static void setPlaceVariables(EditCommand editCommand, String value) {
		editCommand.isEditingPlace = true;
		editCommand.newTaskDetails.place = value;
	}

	private static void setDescriptionVariables(EditCommand editCommand,
			String value) {
		editCommand.isEditingDescription = true;
		editCommand.newTaskDetails.description = value;
	}

	private static void setTitleVariables(EditCommand editCommand, String tag,
			String value) throws InvalidInputException {
		checkForEmptyValue(value, tag);
		editCommand.isEditingTitle = true;
		editCommand.newTaskDetails.title = value;
	}

}
